home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / ip.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  14KB  |  547 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6.  
  7. /****************************************************************************
  8. *    $Id: ip.c 1.2 93/07/16 11:45:36 ROOT_DOS Exp $
  9. *    14 Jun 93    1.2        GT    Fix warnings.                                    *
  10. *
  11. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  12. *
  13. ****************************************************************************/
  14.  
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "timer.h"
  18. #include "internet.h"
  19. #include "netuser.h"
  20. #include "iface.h"
  21. #include "pktdrvr.h"
  22. #include "ip.h"
  23. #include "icmp.h"
  24.  
  25. static struct mbuf *fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  26. static void ip_timeout __ARGS((void *arg));
  27. static void free_reasm __ARGS((struct reasm *rp));
  28. static void freefrag __ARGS((struct frag *fp));
  29. static struct reasm *lookup_reasm __ARGS((struct ip *ip));
  30. static struct reasm *creat_reasm __ARGS((struct ip *ip));
  31. static struct frag *newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  32.  
  33. struct mib_entry Ip_mib[20] = {
  34.     { "",            0 },
  35.     { "ipForwarding",        1 },
  36.     { "ipDefaultTTL",        MAXTTL },
  37.     { "ipInReceives",        0 },
  38.     { "ipInHdrErrors",    0 },
  39.     { "ipInAddrErrors",    0 },
  40.     { "ipForwDatagrams",    0 },
  41.     { "ipInUnknownProtos",    0 },
  42.     { "ipInDiscards",        0 },
  43.     { "ipInDelivers",        0 },
  44.     { "ipOutRequests",    0 },
  45.     { "ipOutDiscards",    0 },
  46.     { "ipOutNoRoutes",    0 },
  47.     { "ipReasmTimeout",    TLB },
  48.     { "ipReasmReqds",        0 },
  49.     { "ipReasmOKs",        0 },
  50.     { "ipReasmFails",        0 },
  51.     { "ipFragOKs",        0 },
  52.     { "ipFragFails",        0 },
  53.     { "ipFragCreates",    0 },
  54. };
  55.  
  56. struct reasm *Reasmq;
  57. static struct raw_ip *Raw_ip;
  58.  
  59. #define    INSERT    0
  60. #define    APPEND    1
  61. #define    PREPEND    2
  62.  
  63. /* Send an IP datagram. Modeled after the example interface on p 32 of
  64.  * RFC 791
  65.  */
  66.  
  67. int ip_send(
  68.     int32 source,            /* source address */
  69.     int32 dest,                /* Destination address */
  70.     char protocol,            /* Protocol */
  71.     char tos,                /* Type of service */
  72.     char ttl,                /* Time-to-live */
  73.     struct mbuf *bp,        /* Data portion of datagram */
  74.     int16 length,            /* Optional length of data portion */
  75.     int16 id,                /* Optional identification */
  76.     char df )                /* Don't-fragment flag */
  77. {
  78.     struct mbuf *tbp;
  79.     struct ip ip;            /* IP header */
  80.     static int16 id_cntr = 0;    /* Datagram serial number */
  81.     struct phdr phdr;
  82.  
  83.     ipOutRequests++;
  84.  
  85.     if(source == INADDR_ANY)
  86.         source = locaddr(dest);
  87.     if(length == 0 && bp != NULLBUF)
  88.         length = len_p(bp);
  89.     if(id == 0)
  90.         id = id_cntr++;        
  91.     if(ttl == 0)
  92.         ttl = ipDefaultTTL;
  93.  
  94.     /* Fill in IP header */
  95.     ip.version = IPVERSION;
  96.     ip.tos = tos;
  97.     ip.length = IPLEN + length;
  98.     ip.id = id;
  99.     ip.offset = 0;
  100.     ip.flags.mf = 0;
  101.     ip.flags.df = df;
  102.     ip.flags.congest = 0;
  103.     ip.ttl = ttl;
  104.     ip.protocol = protocol;
  105.     ip.source = source;
  106.     ip.dest = dest;
  107.     ip.optlen = 0;
  108.     if((tbp = htonip(&ip,bp,IP_CS_NEW)) == NULLBUF){
  109.         free_p(bp);
  110.         return -1;
  111.     }
  112.     if((bp = pushdown(tbp,sizeof(phdr))) == NULLBUF){
  113.         free_p(tbp);
  114.         return -1;
  115.     }
  116.     if(ismyaddr(ip.dest)){
  117.         /* Pretend it has been sent by the loopback interface before
  118.          * it appears in the receive queue
  119.          */
  120.         phdr.iface = &Loopback;
  121.         Loopback.ipsndcnt++;
  122.         Loopback.rawsndcnt++;
  123.         Loopback.lastsent = secclock();
  124.     } else
  125.         phdr.iface = NULLIF;
  126.     phdr.type = CL_NONE;
  127.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  128.     enqueue(&Hopper,bp);
  129.     return 0;
  130. }
  131.  
  132. /* Reassemble incoming IP fragments and dispatch completed datagrams
  133.  * to the proper transport module
  134.  */
  135. void
  136. ip_recv(iface,ip,bp,rxbroadcast)
  137. struct iface *iface;    /* Incoming interface */
  138. struct ip *ip;        /* Extracted IP header */
  139. struct mbuf *bp;    /* Data portion */
  140. int rxbroadcast;    /* True if received on subnet broadcast address */
  141. {
  142.     /* Function to call with completed datagram */
  143.     register struct raw_ip *rp;
  144.     struct mbuf *bp1,*tbp;
  145.     int rxcnt = 0;
  146.     register struct iplink *ipp;
  147.  
  148.     /* If we have a complete packet, call the next layer
  149.      * to handle the result. Note that fraghandle passes back
  150.      * a length field that does NOT include the IP header
  151.      */
  152.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  153.         return;        /* Not done yet */
  154.  
  155.     ipInDelivers++;
  156.  
  157.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  158.         if(rp->protocol != ip->protocol)
  159.             continue;
  160.         rxcnt++;
  161.         /* Duplicate the data portion, and put the header back on */
  162.         dup_p(&bp1,bp,0,len_p(bp));
  163.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1,IP_CS_OLD)) != NULLBUF){
  164.             enqueue(&rp->rcvq,tbp);
  165.             if(rp->r_upcall != NULLVFP)
  166.                 (*rp->r_upcall)(rp);
  167.         } else {
  168.             free_p(bp1);
  169.         }
  170.     }
  171.     /* Look it up in the transport protocol table */
  172.     for(ipp = Iplink;ipp->funct != NULL;ipp++){
  173.         if(ipp->proto == ip->protocol)
  174.             break;
  175.     }
  176.     if(ipp->funct != NULL){
  177.         /* Found, call transport protocol */
  178.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  179.     } else {
  180.         /* Not found */
  181.         if(rxcnt == 0){
  182.             /* Send an ICMP Protocol Unknown response... */
  183.             ipInUnknownProtos++;
  184.             /* ...unless it's a broadcast */
  185.             if(!rxbroadcast){
  186.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  187.                  ICMP_PROT_UNREACH,NULLICMP);
  188.             }
  189.         }
  190.         free_p(bp);
  191.     }
  192. }
  193. /* Handle IP packets encapsulated inside IP */
  194. void
  195. ipip_recv(iface,ip,bp,rxbroadcast)
  196. struct iface *iface;    /* Incoming interface */
  197. struct ip *ip;        /* Extracted IP header */
  198. struct mbuf *bp;    /* Data portion */
  199. int rxbroadcast;    /* True if received on subnet broadcast address */
  200. {
  201.     struct phdr phdr;
  202.     struct mbuf *tbp;
  203.  
  204.     if((tbp = pushdown(bp,sizeof(phdr))) == NULLBUF){
  205.         free_p(bp);
  206.         return;
  207.     }
  208.     bp = tbp;
  209.     phdr.iface = &Encap;
  210.     phdr.type = CL_NONE;
  211.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  212.     enqueue(&Hopper,bp);
  213. }
  214.  
  215. /* Process IP datagram fragments
  216.  * If datagram is complete, return it with ip->length containing the data
  217.  * length (MINUS header); otherwise return NULLBUF
  218.  */
  219. static
  220. struct mbuf *
  221. fraghandle(ip,bp)
  222. struct ip *ip;        /* IP header, host byte order */
  223. struct mbuf *bp;    /* The fragment itself */
  224. {
  225.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  226.     struct frag *lastfrag,*nextfrag,*tfp;
  227.     struct mbuf *tbp;
  228.     int16 i;
  229.     int16 last;        /* Index of first byte beyond fragment */
  230.  
  231.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  232.  
  233.     rp = lookup_reasm(ip);
  234.     if(ip->offset == 0 && !ip->flags.mf){
  235.         /* Complete datagram received. Discard any earlier fragments */
  236.         if(rp != NULLREASM){
  237.             free_reasm(rp);
  238.             ipReasmOKs++;
  239.         }
  240.         return bp;
  241.     }
  242.     ipReasmReqds++;
  243.     if(rp == NULLREASM){
  244.         /* First fragment; create new reassembly descriptor */
  245.         if((rp = creat_reasm(ip)) == NULLREASM){
  246.             /* No space for descriptor, drop fragment */
  247.             ipReasmFails++;
  248.             free_p(bp);
  249.             return NULLBUF;
  250.         }
  251.     }
  252.     /* Keep restarting timer as long as we keep getting fragments */
  253.     stop_timer(&rp->timer);
  254.     start_timer(&rp->timer);
  255.  
  256.     /* If this is the last fragment, we now know how long the
  257.      * entire datagram is; record it
  258.      */
  259.     if(!ip->flags.mf)
  260.         rp->length = last;
  261.  
  262.     /* Set nextfrag to the first fragment which begins after us,
  263.      * and lastfrag to the last fragment which begins before us
  264.      */
  265.     lastfrag = NULLFRAG;
  266.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  267.         if(nextfrag->offset > ip->offset)
  268.             break;
  269.         lastfrag = nextfrag;
  270.     }
  271.     /* Check for overlap with preceeding fragment */
  272.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  273.         /* Strip overlap from new fragment */
  274.         i = lastfrag->last - ip->offset;
  275.         pullup(&bp,NULLCHAR,i);
  276.         if(bp == NULLBUF)
  277.             return NULLBUF;    /* Nothing left */
  278.         ip->offset += i;
  279.     }
  280.     /* Look for overlap with succeeding segments */
  281.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  282.         tfp = nextfrag->next;    /* save in case we delete fp */
  283.  
  284.         if(nextfrag->offset >= last)
  285.             break;    /* Past our end */
  286.         /* Trim the front of this entry; if nothing is
  287.          * left, remove it.
  288.          */
  289.         i = last - nextfrag->offset;
  290.         pullup(&nextfrag->buf,NULLCHAR,i);
  291.         if(nextfrag->buf == NULLBUF){
  292.             /* superseded; delete from list */
  293.             if(nextfrag->prev != NULLFRAG)
  294.                 nextfrag->prev->next = nextfrag->next;
  295.             else
  296.                 rp->fraglist = nextfrag->next;
  297.             if(tfp->next != NULLFRAG)
  298.                 nextfrag->next->prev = nextfrag->prev;
  299.             freefrag(nextfrag);
  300.         } else
  301.             nextfrag->offset = last;
  302.     }
  303.     /* Lastfrag now points, as before, to the fragment before us;
  304.      * nextfrag points at the next fragment. Check to see if we can
  305.      * join to either or both fragments.
  306.      */
  307.     i = INSERT;
  308.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  309.         i |= APPEND;
  310.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  311.         i |= PREPEND;
  312.     switch(i){
  313.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  314.         tfp = newfrag(ip->offset,last,bp);
  315.         tfp->prev = lastfrag;
  316.         tfp->next = nextfrag;
  317.         if(lastfrag != NULLFRAG)
  318.             lastfrag->next = tfp;    /* Middle of list */
  319.         else
  320.             rp->fraglist = tfp;    /* First on list */
  321.         if(nextfrag != NULLFRAG)
  322.             nextfrag->prev = tfp;
  323.         break;
  324.     case APPEND:    /* Append to lastfrag */
  325.         append(&lastfrag->buf,bp);
  326.         lastfrag->last = last;    /* Extend forward */
  327.         break;
  328.     case PREPEND:    /* Prepend to nextfrag */
  329.         tbp = nextfrag->buf;
  330.         nextfrag->buf = bp;
  331.         append(&nextfrag->buf,tbp);
  332.         nextfrag->offset = ip->offset;    /* Extend backward */
  333.         break;
  334.     case (APPEND|PREPEND):
  335.         /* Consolidate by appending this fragment and nextfrag
  336.          * to lastfrag and removing the nextfrag descriptor
  337.          */
  338.         append(&lastfrag->buf,bp);
  339.         append(&lastfrag->buf,nextfrag->buf);
  340.         nextfrag->buf = NULLBUF;
  341.         lastfrag->last = nextfrag->last;
  342.  
  343.         /* Finally unlink and delete the now unneeded nextfrag */
  344.         lastfrag->next = nextfrag->next;
  345.         if(nextfrag->next != NULLFRAG)
  346.             nextfrag->next->prev = lastfrag;
  347.         freefrag(nextfrag);
  348.         break;
  349.     }
  350.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  351.         && rp->length != 0){
  352.         /* We've gotten a complete datagram, so extract it from the
  353.          * reassembly buffer and pass it on.
  354.          */
  355.         bp = rp->fraglist->buf;
  356.         rp->fraglist->buf = NULLBUF;
  357.         /* Tell IP the entire length */
  358.         ip->length = rp->length + (IPLEN + ip->optlen);
  359.         free_reasm(rp);
  360.         ipReasmOKs++;
  361.         return bp;
  362.     } else
  363.         return NULLBUF;
  364. }
  365. /* Arrange for receipt of raw IP datagrams */
  366. struct raw_ip *
  367. raw_ip(protocol,r_upcall)
  368. int protocol;
  369. void (*r_upcall)();
  370. {
  371.     register struct raw_ip *rp;
  372.  
  373.     rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  374.     rp->protocol = protocol;
  375.     rp->r_upcall = r_upcall;
  376.     rp->next = Raw_ip;
  377.     Raw_ip = rp;
  378.     return rp;
  379. }
  380. /* Free a raw IP descriptor */
  381. void
  382. del_ip(rpp)
  383. struct raw_ip *rpp;
  384. {
  385.     struct raw_ip *rplast = NULLRIP;
  386.     register struct raw_ip *rp;
  387.  
  388.     /* Do sanity check on arg */
  389.     for(rp = Raw_ip;rp != NULLRIP;rplast=rp,rp = rp->next)
  390.         if(rp == rpp)
  391.             break;
  392.     if(rp == NULLRIP)
  393.         return;    /* Doesn't exist */
  394.  
  395.     /* Unlink */
  396.     if(rplast != NULLRIP)
  397.         rplast->next = rp->next;
  398.     else
  399.         Raw_ip = rp->next;
  400.     /* Free resources */
  401.     free_q(&rp->rcvq);
  402.     free((char *)rp);
  403. }
  404.  
  405. static struct reasm *
  406. lookup_reasm(ip)
  407. struct ip *ip;
  408. {
  409.     register struct reasm *rp;
  410.     struct reasm *rplast = NULLREASM;
  411.  
  412.     for(rp = Reasmq;rp != NULLREASM;rplast=rp,rp = rp->next){
  413.         if(ip->id == rp->id && ip->source == rp->source
  414.          && ip->dest == rp->dest && ip->protocol == rp->protocol){
  415.             if(rplast != NULLREASM){
  416.                 /* Move to top of list for speed */
  417.                 rplast->next = rp->next;
  418.                 rp->next = Reasmq;
  419.                 Reasmq = rp;
  420.             }
  421.             return rp;
  422.         }
  423.  
  424.     }
  425.     return NULLREASM;
  426. }
  427. /* Create a reassembly descriptor,
  428.  * put at head of reassembly list
  429.  */
  430. static struct reasm *
  431. creat_reasm(ip)
  432. register struct ip *ip;
  433. {
  434.     register struct reasm *rp;
  435.  
  436.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  437.         return rp;    /* No space for descriptor */
  438.     rp->source = ip->source;
  439.     rp->dest = ip->dest;
  440.     rp->id = ip->id;
  441.     rp->protocol = ip->protocol;
  442.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  443.     rp->timer.func = ip_timeout;
  444.     rp->timer.arg = rp;
  445.  
  446.     rp->next = Reasmq;
  447.     Reasmq = rp;
  448.     return rp;
  449. }
  450.  
  451. /* Free all resources associated with a reassembly descriptor */
  452. static void
  453. free_reasm(r)
  454. struct reasm *r;
  455. {
  456.     register struct reasm *rp;
  457.     struct reasm *rplast = NULLREASM;
  458.     register struct frag *fp;
  459.  
  460.     for(rp = Reasmq;rp != NULLREASM;rplast = rp,rp=rp->next)
  461.         if(r == rp)
  462.             break;
  463.     if(rp == NULLREASM)
  464.         return;    /* Not on list */
  465.  
  466.     stop_timer(&rp->timer);
  467.     /* Remove from list of reassembly descriptors */
  468.     if(rplast != NULLREASM)
  469.         rplast->next = rp->next;
  470.     else
  471.         Reasmq = rp->next;
  472.  
  473.     /* Free any fragments on list, starting at beginning */
  474.     while((fp = rp->fraglist) != NULLFRAG){
  475.         rp->fraglist = fp->next;
  476.         free_p(fp->buf);
  477.         free((char *)fp);
  478.     }
  479.     free((char *)rp);
  480. }
  481.  
  482. /* Handle reassembly timeouts by deleting all reassembly resources */
  483. static void
  484. ip_timeout(arg)
  485. void *arg;
  486. {
  487.     register struct reasm *rp;
  488.  
  489.     rp = (struct reasm *)arg;
  490.     free_reasm(rp);
  491.     ipReasmFails++;
  492. }
  493. /* Create a fragment */
  494.  
  495. static struct frag *newfrag(
  496.     int16 offset,
  497.     int16    last,
  498.     struct mbuf *bp )
  499. {
  500.     struct frag *fp;
  501.  
  502.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  503.         /* Drop fragment */
  504.         free_p(bp);
  505.         return NULLFRAG;
  506.     }
  507.     fp->buf = bp;
  508.     fp->offset = offset;
  509.     fp->last = last;
  510.     return fp;
  511. }
  512. /* Delete a fragment, return next one on queue */
  513. static void
  514. freefrag(fp)
  515. struct frag *fp;
  516. {
  517.     free_p(fp->buf);
  518.     free((char *)fp);
  519. }
  520.  
  521. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  522.  * each fragment on each reassembly descriptor
  523.  */
  524. void
  525. ip_garbage(red)
  526. int red;
  527. {
  528.     struct reasm *rp,*rp1;
  529.     struct frag *fp;
  530.     struct raw_ip *rwp;
  531.  
  532.     /* Run through the reassembly queue */
  533.     for(rp = Reasmq;rp != NULLREASM;rp = rp1){
  534.         rp1 = rp->next;
  535.         if(red){
  536.             free_reasm(rp);
  537.         } else {
  538.             for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  539.                 mbuf_crunch(&fp->buf);
  540.             }
  541.         }
  542.     }
  543.     /* Run through the raw IP queue */
  544.     for(rwp = Raw_ip;rwp != NULLRIP;rwp = rwp->next)
  545.         mbuf_crunch(&rwp->rcvq);
  546. }
  547.